﻿using Arric.Crypto.SM.SM4;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Configuration;
using System.IO;
using System.Text;

namespace com.lythen.file.Security
{
    /***************************************************************************
     * CLR版本：4.0.30319.42000
     *唯一标识：2477da42-2ede-4f81-83e5-4875bcaabb3d
     *  创建人：赖仁良
     *创建时间：2023/12/20 12:07:42
     *功能描述：
     * ----------------------------------------------------------------
     * 修改人：
     * 时间：
     * 修改说明：
     *=========================================================================*/
    /// <summary>
    /// 国密算法
    /// </summary>
    public class SMSecurity
    {
        private static SMSecurity m_instance = new SMSecurity();
        public string PublicKeyFile { get; } = Path.GetFullPath("./PublicKey.key");
        public string PrivateKeyFile { get; } = Path.GetFullPath("./PrivateKey.key");

        public static SMSecurity Instance
        {
            get
            {
                return m_instance;
            }
        }

        private string publicKey = "04A836CAE9D5B2448A78B3215D9C43CE90C8D30D2C8CA34ABC26C598986CB8ADB0DC5DEA11F0CEACE05C62448A7978F38B1434A965F43F89CB3A8E51F05B7DF872";
        private string privateKey = "6B4A5716AB8F9E979F55B07DD8BF4493BC32DA81E7ED72ECDDA2AA1783FE9FC7";

        AsymmetricKeyParameter publicKeyParameter;
        AsymmetricKeyParameter bcecPrivateKey;

        private string sm4SecretKey = "U/QazwSDxnUNp3l19x227aWMPatJZComkfAZblTexOc=";
        private string iv = "gee6p+i0qOajgOW3peWFt+mbhue+pOabtOaWsOaWueahiA0K55yB57qn6LSo";
        private Sm4Crypto sm4Crypto;
        private SMSecurity()
        {
            init();
        }
        /// <summary>
        /// 独立实例化的入口，可以自定义密码。
        /// 这个主要是可以在不同的地方使用不同密码
        /// </summary>
        /// <param name="secretKey"></param>
        /// <param name="iv"></param>
        public SMSecurity(string secretKey, string iv)
        {
            this.sm4SecretKey = secretKey;
            this.iv = iv;
            init();

        }
        private void init()
        {
            if (!string.IsNullOrWhiteSpace(PublicKeyFile) && File.Exists(PublicKeyFile))
            {
                publicKey = File.ReadAllText(PublicKeyFile);
            }
            if (!string.IsNullOrWhiteSpace(PrivateKeyFile) && File.Exists(PrivateKeyFile))
            {
                privateKey = File.ReadAllText(PrivateKeyFile);
            }
            sm4Crypto = new Sm4Crypto();
            sm4Crypto.Encoding = System.Text.Encoding.UTF8;

            // 处理SM2密钥
            if (this.publicKey.Length == 130)
            {
                this.publicKey = this.publicKey.Substring(2, 128);
            }
            //公钥X，前64位
            String x = this.publicKey.Substring(0, 64);
            //公钥Y，后64位
            String y = this.publicKey.Substring(64);
            //获取公钥对象
            publicKeyParameter = GmUtil.GetPublickeyFromXY(new BigInteger(x, 16), new BigInteger(y, 16));

            BigInteger d = new BigInteger(this.privateKey, 16);
            bcecPrivateKey = GmUtil.GetPrivatekeyFromD(d);

        }
        /// <summary>
        /// SM2公钥加密，返回16进制字符串
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public string SM2EncryptByPublicKey(string Plaintext)
        {
            var digestByte = SM2EncryptBytesByPublicKey(Plaintext);
            return Hex.ToHexString(digestByte);
        }
        public byte[] SM2EncryptBytesByPublicKey(string Plaintext)
        {
            return GmUtil.Sm2Encrypt(Encoding.UTF8.GetBytes(Plaintext), publicKeyParameter);

        }
        public byte[] SM2EncryptBytesByPublicKey(byte[] byToEncrypt)
        {
            return GmUtil.Sm2Encrypt(byToEncrypt, publicKeyParameter);

        }
        /// <summary>
        /// SM2私钥解密，返回UTF8文本
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public string SM2DecryptByPrivateKey(string encText)
        {
            var byDecrypted = SM2DecryptBytesByPrivateKey(encText);
            return Encoding.UTF8.GetString(byDecrypted);
        }
        public byte[] SM2DecryptBytesByPrivateKey(string encText)
        {
            byte[] byToDecrypt = Hex.Decode(encText);
            return GmUtil.Sm2Decrypt(byToDecrypt, bcecPrivateKey);
        }
        public byte[] SM2DecryptBytesByPrivateKey(byte[] byToDecrypt)
        {
            return GmUtil.Sm2Decrypt(byToDecrypt, bcecPrivateKey);
        }
        /// <summary>
        /// 对称加密
        /// 密文分组链接方式，首组用到IV，后一组用到前一组的输出，内容相同的组加密结果不同。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public string SM4EncryptCBC(string text)
        {
            return sm4Crypto.EncryptCBCToBase64(text, this.sm4SecretKey, this.iv);
        }
        /// <summary>
        /// 对称加密
        /// 密文分组链接方式，首组用到IV，后一组用到前一组的输出，内容相同的组加密结果不同。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public string SM4DecryptCBC(string text)
        {
            return sm4Crypto.DecryptCBCFormBase64(text, this.sm4SecretKey, this.iv);
        }
        /// <summary>
        /// 电码本模式，16字节一分组，组和组之间没有关系，组内容相同加密结果相同。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public string SM4EncryptECB(string text)
        {
            return sm4Crypto.EncryptECBToBase64(text, this.sm4SecretKey);
        }
        /// <summary>
        /// 电码本模式，16字节一分组，组和组之间没有关系，组内容相同加密结果相同。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public string SM4DecryptECB(string text)
        {
            return sm4Crypto.DecryptECBFormBase64(text, this.sm4SecretKey);
        }
    }
}
